package com.alibaba.citrus.cr.mn.order.center.facade.function.assemble.impl;

import com.alibaba.citrus.cr.common.enums.GeneralStatusEnum;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.BizInventoryQueryAdapter;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.CargoZoneAdapter;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.dataobject.request.InventoryAvailableQtyQueryRequest;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.dataobject.request.LogisticWarehouseQueryRequest;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.dataobject.response.InventoryAvailableQtyQueryDTO;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.dataobject.response.ItemSearchAbilityDTO;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.dataobject.response.LogisticWarehouseQueryDTO;
import com.alibaba.citrus.cr.mn.order.center.facade.function.assemble.OrderBizAssemble;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.mnordercenter.orderbaserequest.OrderAtomUpdateRequest;
import com.epoch.app.mnordercenter.orderbaserequest.OrderBizUpdateRequest;
import com.epoch.app.mnordercenter.orderbaserequest.OrderLineAtomUpdateRequest;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author zhangxiaorui
 * @ClassName OrderUpdateBizAssembleOfInventoryCenter
 * @description: 订单商业修改统一物料、库存校验
 * @date 2023/05/17 09:53
 * @version: 1.0
 */
@Service
@Order(3)
public class OrderUpdateBizAssembleOfInventoryCenter implements OrderBizAssemble<OrderBizUpdateRequest> {
    private static final Log log = Log.getLogger(OrderUpdateBizAssembleOfInventoryCenter.class);

    @Resource
    private BizInventoryQueryAdapter bizInventoryQueryAdapter;

    @Resource
    private CargoZoneAdapter cargoZoneAdapter;

    @Override
    public Map<String, Object> query(OrderBizUpdateRequest exchangeOrderBizCreateRequest) {
        return query(Lists.newArrayList(exchangeOrderBizCreateRequest));
    }

    @Override
    public Map<String, Object> query(List<OrderBizUpdateRequest> exchangeOrderBizCreateRequests) {
        try {
            // Key：库存工厂Code+库存地点Code or 逻辑仓库Code
            Map<String, LogisticWarehouseQueryDTO> logisticWarehouseQueryMap = queryLogisticWarehouseInfoList(exchangeOrderBizCreateRequests);
            log.info("OrderUpdateBizAssembleOfInventoryCenter#query logisticWarehouseQueryMap: {}", logisticWarehouseQueryMap);
            // 库存可用数量
            Map<String, InventoryAvailableQtyQueryDTO> inventoryAvailableQtyQueryMap =
                    queryInventoryAvailableQty(exchangeOrderBizCreateRequests, logisticWarehouseQueryMap);
            log.info("OrderUpdateBizAssembleOfInventoryCenter#query inventoryAvailableQtyQueryMap: {}", inventoryAvailableQtyQueryMap);

            Map<String, Object> result = Maps.newHashMap();
            result.put(LOGISTIC_WAREHOUSE, logisticWarehouseQueryMap);
            result.put(INVENTORY_AVAILABLE_QTY, inventoryAvailableQtyQueryMap);
            log.info("修改订单商业能力库存中心数据组装结果 result={}", JSONObject.toJSONString(result));
            return result;
        } catch (Exception e) {
            log.error("修改订单商业能力库存中心数据组装失败", e);
            throw new RuntimeException(e);
        }
    }

    @Override
    public Result<String> assemble(Map<String, Object> queryResponseMap, OrderBizUpdateRequest orderBizUpdateRequest) {
        // Key：库存工厂Code+库存地点Code or 逻辑仓库Code
        Map<String, LogisticWarehouseQueryDTO> logisticWarehouseMap = getBizInfoMap(queryResponseMap, LOGISTIC_WAREHOUSE, LogisticWarehouseQueryDTO.class);
        // 库存可用数量
        Map<String, InventoryAvailableQtyQueryDTO> inventoryAvailableQtyMap = getBizInfoMap(queryResponseMap, INVENTORY_AVAILABLE_QTY, InventoryAvailableQtyQueryDTO.class);
        log.info("inventoryAvailableQtyMap参数:{}", JSON.toJSONString(inventoryAvailableQtyMap));
        // 物料
        Map<String, ItemSearchAbilityDTO> scItemInfoMap = getBizInfoMap(queryResponseMap, SC_ITEM_INFO, ItemSearchAbilityDTO.class);

        Map<String, String> salesQty4ProductMap = Maps.newConcurrentMap();
        for (OrderLineAtomUpdateRequest orderDetail : orderBizUpdateRequest.getOrderDetails()) {
            // Key：库存工厂Code+库存地点Code or 逻辑仓库Code
            String warehouseKey = orderDetail.getShippingWarehouseCode();
            if (StringUtils.isBlank(warehouseKey)) {
                if (StringUtils.isNotBlank(orderDetail.getDeliveryFactoryCode()) && StringUtils.isNotBlank(orderDetail.getStockCode())) {
                    warehouseKey = String.format("%s_%s", orderDetail.getDeliveryFactoryCode(), orderDetail.getStockCode());
                }
            }
            // 缓存里取出仓库信息
            if (StringUtils.isNotBlank(warehouseKey)) {
                LogisticWarehouseQueryDTO logisticWarehouseQueryDTO = logisticWarehouseMap.get(warehouseKey);
                log.info("OrderUpdateBizAssembleOfInventoryCenter#assemble logisticWarehouseQueryDTO: {}", logisticWarehouseQueryDTO);
                if (Objects.isNull(logisticWarehouseQueryDTO)) {
                    return Result.fail(orderBizUpdateRequest.getSalesOrderNo(), "OC-01-003-01-16-011", "逻辑仓不存在:" + warehouseKey);
                }
                if (Objects.nonNull(logisticWarehouseQueryDTO.getStatus()) && !GeneralStatusEnum.YES.getCode().equals(logisticWarehouseQueryDTO.getStatus())) {
                    return Result.fail(orderBizUpdateRequest.getSalesOrderNo(), "OC-01-003-01-16-012", "逻辑仓已禁用:" + logisticWarehouseQueryDTO.getCode());
                }

                log.info("OrderUpdateBizAssembleOfInventoryCenter#assemble orderDetail: {}", JSON.toJSONString(orderDetail));
                
                orderDetail.setShippingWarehouseCode(logisticWarehouseQueryDTO.getCode());
                orderDetail.setShippingWarehouseName(logisticWarehouseQueryDTO.getName());
                orderDetail.setDeliveryFactoryCode(logisticWarehouseQueryDTO.getSapFactoryCode());
                orderDetail.setStockCode(logisticWarehouseQueryDTO.getWarehouseCode());
                
                log.info("OrderUpdateBizAssembleOfInventoryCenter#assemble orderDetail: {}", JSON.toJSONString(orderDetail));
                
                if (!orderBizUpdateRequest.getCheckStock()) {
                    // 入参明确标识不校验库存时跳过库存校验逻辑
                    continue;
                }

                // 校验销售/换货物料的库存
                // 缓存里取出物料信息
                ItemSearchAbilityDTO scItem = scItemInfoMap.get(orderDetail.getProductCode());
                log.info("OrderUpdateBizAssembleOfInventoryCenter#assemble scItem: {}", scItem);
                if (Objects.isNull(scItem)) {
                    return Result.fail(orderBizUpdateRequest.getSalesOrderNo(), "OC-01-001-01-16-012", "物料编码不存在");
                }

                String inventoryAvailableQtyKey = logisticWarehouseQueryDTO.getCode() + "_" + scItem.getScItemId();
                // 库存可用数量
                InventoryAvailableQtyQueryDTO inventoryAvailableQty = inventoryAvailableQtyMap.get(inventoryAvailableQtyKey);
                log.info("OrderUpdateBizAssembleOfInventoryCenter#assemble inventoryAvailableQty: {}", inventoryAvailableQty);

                // 当前行的库存可用量校验
                if (Objects.isNull(inventoryAvailableQty)) {
                    return Result.fail(orderBizUpdateRequest.getSalesOrderNo(), "OC-01-001-01-16-046", "库存可用余量小于销售数量");
                }
                if (Objects.isNull(inventoryAvailableQty.getAvailableQuantity())) {
                    return Result.fail(orderBizUpdateRequest.getSalesOrderNo(), "OC-01-001-01-16-046", "库存可用余量小于销售数量");
                }
                if (StringUtils.isBlank(orderDetail.getProductQuantity())) {
                    return Result.fail(orderBizUpdateRequest.getSalesOrderNo(), "OC-01-001-01-15-001", "参数【销售数量】不能为空");
                }
                BigDecimal currAvailableQty = new BigDecimal(inventoryAvailableQty.getAvailableQuantity()).divide(new BigDecimal("1000"), 3, RoundingMode.HALF_UP);
                log.info("OrderUpdateBizAssembleOfInventoryCenter#assemble currAvailableQty: {}", currAvailableQty);
                BigDecimal totalQuantity = calSalesTotalQuantity(inventoryAvailableQtyKey, salesQty4ProductMap, orderDetail);
                log.info("OrderUpdateBizAssembleOfInventoryCenter#assemble totalQuantity: {}", totalQuantity);
                // 当前可用库存量和请求总库存进行比较
                if (totalQuantity.compareTo(currAvailableQty) > 0) {
                    return Result.fail(orderBizUpdateRequest.getSalesOrderNo(), "OC-01-001-01-16-046", "库存可用余量小于销售数量");
                }
            }
        }
        return Result.success(null);
    }

    private BigDecimal calSalesTotalQuantity(String key, Map<String, String> salesQty4ProductMap, OrderLineAtomUpdateRequest orderDetail) {
        String currSalesTotalQty = salesQty4ProductMap.getOrDefault(key, "0");
        BigDecimal currentSaleUnitQty = new BigDecimal(orderDetail.getProductQuantity()).divide(new BigDecimal(orderDetail.getUnitConversionRelationship()),3, RoundingMode.HALF_UP);
        BigDecimal addedQty = currentSaleUnitQty.add(new BigDecimal(currSalesTotalQty));
        salesQty4ProductMap.put(key, addedQty.toPlainString());
        return addedQty;
    }

    private Map<String, LogisticWarehouseQueryDTO> queryLogisticWarehouseInfoList(List<OrderBizUpdateRequest> salesOrderBizCreateRequests) {
        List<LogisticWarehouseQueryRequest> logisticWarehouseQueryRequests = Lists.newArrayList();
        Set<String> dupLogisticWarehouseCode = Sets.newHashSet();
        Set<String> dupAddressAndFactoryCode = Sets.newHashSet();
        for (OrderAtomUpdateRequest updateRequest : salesOrderBizCreateRequests) {
            for (OrderLineAtomUpdateRequest orderDetail : updateRequest.getOrderDetails()) {
                if (StringUtils.isNotBlank(orderDetail.getShippingWarehouseCode())) {
                    if (!dupLogisticWarehouseCode.contains(orderDetail.getShippingWarehouseCode())) {
                        LogisticWarehouseQueryRequest queryRequest = new LogisticWarehouseQueryRequest();
                        queryRequest.setLogicWarehouseCode(orderDetail.getShippingWarehouseCode());
                        logisticWarehouseQueryRequests.add(queryRequest);

                        dupLogisticWarehouseCode.add(orderDetail.getShippingWarehouseCode());
                    }
                } else if (StringUtils.isNotBlank(orderDetail.getDeliveryFactoryCode()) && StringUtils.isNotBlank(orderDetail.getStockCode())) {
                    if (!dupAddressAndFactoryCode.contains(String.format("%s_%s", orderDetail.getDeliveryFactoryCode(), orderDetail.getStockCode()))) {
                        LogisticWarehouseQueryRequest queryRequest = new LogisticWarehouseQueryRequest();
                        queryRequest.setFactoryCode(orderDetail.getDeliveryFactoryCode());
                        queryRequest.setStorageLocation(orderDetail.getStockCode());
                        logisticWarehouseQueryRequests.add(queryRequest);

                        dupAddressAndFactoryCode.add(String.format("%s_%s", orderDetail.getDeliveryFactoryCode(), orderDetail.getStockCode()));
                    }
                }
            }
        }

        if (CollectionUtils.isEmpty(logisticWarehouseQueryRequests)) {
            return Maps.newHashMap();
        }

        List<LogisticWarehouseQueryDTO> listResult = cargoZoneAdapter.queryCargoZoneListByParam(logisticWarehouseQueryRequests);
        if (CollectionUtils.isEmpty(listResult)) {
            return Maps.newHashMap();
        }
        Map<String, LogisticWarehouseQueryDTO> logisticWarehouseQueryResponseMap = Maps.newHashMap();
        for (LogisticWarehouseQueryDTO logisticWarehouseQueryResponse : listResult) {
            String factoryStockCode = String.format("%s_%s", logisticWarehouseQueryResponse.getSapFactoryCode(), logisticWarehouseQueryResponse.getWarehouseCode());
            logisticWarehouseQueryResponseMap.put(factoryStockCode, logisticWarehouseQueryResponse);
            logisticWarehouseQueryResponseMap.put(logisticWarehouseQueryResponse.getCode(), logisticWarehouseQueryResponse);
        }

        return logisticWarehouseQueryResponseMap;
    }

    private Map<String, InventoryAvailableQtyQueryDTO> queryInventoryAvailableQty(List<OrderBizUpdateRequest> orderBizUpdateRequests, Map<String, LogisticWarehouseQueryDTO> logisticWarehouseQueryMap) {

        List<InventoryAvailableQtyQueryRequest> inventoryAvailableQtyQueryRequests = Lists.newArrayList();

        for (OrderAtomUpdateRequest updateRequest : orderBizUpdateRequests) {

            Map<String, List<OrderLineAtomUpdateRequest>> warehouseOfOrderLineList1 = updateRequest.getOrderDetails()
                    .stream()
                    .filter(p -> StringUtils.isNotBlank(p.getShippingWarehouseCode()))
                    .collect(Collectors.groupingBy(OrderLineAtomUpdateRequest::getShippingWarehouseCode));

            warehouseOfOrderLineList1.forEach((warehouseCode, orderLineList) -> {
                List<String> productCodes = orderLineList.stream().map(OrderLineAtomUpdateRequest::getProductCode).distinct().collect(Collectors.toList());

                InventoryAvailableQtyQueryRequest queryRequest = new InventoryAvailableQtyQueryRequest();
                queryRequest.setLogicWarehouseCode(warehouseCode);
                queryRequest.setGoodsCodeList(productCodes);

                inventoryAvailableQtyQueryRequests.add(queryRequest);
            });

            Map<String, List<OrderLineAtomUpdateRequest>> warehouseOfOrderLineList2 = updateRequest.getOrderDetails()
                    .stream()
                    .filter(p -> StringUtils.isNotBlank(p.getDeliveryFactoryCode()) && StringUtils.isNotBlank(p.getStockCode()))
                    .collect(Collectors.groupingBy(p -> String.format("%s_%s", p.getDeliveryFactoryCode(), p.getStockCode())));

            warehouseOfOrderLineList2.forEach((deliveryFactoryStockCode, orderLineList) -> {

                LogisticWarehouseQueryDTO logisticWarehouseQueryDTO = logisticWarehouseQueryMap.get(deliveryFactoryStockCode);
                if (Objects.isNull(logisticWarehouseQueryDTO)) {
                    return;
                }
                List<String> productCodes = orderLineList.stream().map(OrderLineAtomUpdateRequest::getProductCode).distinct().collect(Collectors.toList());

                InventoryAvailableQtyQueryRequest queryRequest = new InventoryAvailableQtyQueryRequest();
                queryRequest.setLogicWarehouseCode(logisticWarehouseQueryDTO.getCode());
                queryRequest.setGoodsCodeList(productCodes);

                inventoryAvailableQtyQueryRequests.add(queryRequest);
            });
        }

        if (CollectionUtils.isEmpty(inventoryAvailableQtyQueryRequests)) {
            return Maps.newHashMap();
        }

        List<InventoryAvailableQtyQueryDTO> inventoryAvailableQtyList = bizInventoryQueryAdapter.queryInventoryAvailableQty(inventoryAvailableQtyQueryRequests);

        if (CollectionUtils.isEmpty(inventoryAvailableQtyList)) {
            return Maps.newHashMap();
        }

        return inventoryAvailableQtyList.stream().collect(Collectors.toMap(p -> p.getWarehouseCode() + "_" + p.getGoodsId(), p -> p, (v1, v2) -> v1));
    }
}
